using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Timers;
using MtApi5;
using MT5Trade.Models;
using NLog;

namespace MT5Trade.Services
{
    /// <summary>
    /// 组合盈亏服务，实现对冲策略的监控与自动平仓
    /// </summary>
    public class CombinedPnLService
    {
        private static readonly Logger Logger = LogManager.GetCurrentClassLogger();

        private MtApi5Client _mainClient;
        private MtApi5Client _followClient;
        private readonly CombinedPnLSettings _settings;
        private readonly Dictionary<string, HedgePair> _hedgePairs;
        private Timer _monitorTimer;
        private readonly object _lockObject = new object();

        private bool _isMonitoring = false;
        private DateTime _lastCheckTime = DateTime.Now;

        public event EventHandler<CombinedPnLResult> OnPnLCalculated;
        public event EventHandler<HedgePair> OnHedgePairClosed;
        public event EventHandler<string> OnError;

        public CombinedPnLService(CombinedPnLSettings settings = null)
        {
            _settings = settings ?? new CombinedPnLSettings();
            _hedgePairs = new Dictionary<string, HedgePair>();
        }

        /// <summary>
        /// 初始化MT5客户端
        /// </summary>
        public void InitializeClients(MtApi5Client mainClient, MtApi5Client followClient)
        {
            _mainClient = mainClient ?? throw new ArgumentNullException(nameof(mainClient));
            _followClient = followClient ?? throw new ArgumentNullException(nameof(followClient));

            if (_monitorTimer == null)
            {
                _monitorTimer = new Timer(_settings.CheckIntervalMs);
                _monitorTimer.Elapsed += MonitorTimer_Elapsed;
                _monitorTimer.AutoReset = true;
            }

            Logger.Info("Combined P&L Service initialized with MT5 clients");
        }

        /// <summary>
        /// 获取当前设置
        /// </summary>
        public CombinedPnLSettings GetSettings()
        {
            return _settings;
        }

        /// <summary>
        /// 计算对冲对的组合盈亏
        /// </summary>
        public CombinedPnLResult CalculateCombinedPnL(HedgePair pair)
        {
            if (_mainClient == null || _followClient == null)
            {
                Logger.Error("MT5 clients not initialized, returning empty result");
                return new CombinedPnLResult { PairId = pair?.GetPairId() ?? "unknown" };
            }

            var startTime = DateTime.Now;

            // 获取实时盈亏
            double mainPnL = GetPositionPnL(_mainClient, pair.MainTicket);
            double followPnL = GetPositionPnL(_followClient, pair.FollowTicket);

            // 计算成本
            double totalCost = CalculateTotalCost(pair);

            // 创建结果对象
            var result = new CombinedPnLResult
            {
                PairId = pair.GetPairId(),
                MainPnL = mainPnL,
                FollowPnL = followPnL,
                TotalCost = totalCost,
                SafetyFactor = _settings.SafetyFactor,
                TargetAmount = _settings.TargetNetProfit,
                CalculationTimeMs = (DateTime.Now - startTime).TotalMilliseconds
            };

            // 计算净盈亏
            result.CalculateNetPnL();

            return result;
        }

        /// <summary>
        /// 开始监控
        /// </summary>
        public void StartMonitoring()
        {
            if (_mainClient == null || _followClient == null)
            {
                Logger.Error("MT5 clients not initialized, cannot start monitoring");
                return;
            }

            if (_isMonitoring) return;

            _isMonitoring = true;
            _monitorTimer.Start();
            Logger.Info("组合盈亏监控已启动");
        }

        /// <summary>
        /// 停止监控
        /// </summary>
        public void StopMonitoring()
        {
            if (!_isMonitoring) return;

            _isMonitoring = false;
            _monitorTimer.Stop();
            Logger.Info("组合盈亏监控已停止");
        }

        /// <summary>
        /// 识别对冲仓位对
        /// </summary>
        public Dictionary<string, HedgePair> IdentifyHedgePairs()
        {
            if (_mainClient == null || _followClient == null)
            {
                Logger.Warn("MT5 clients not initialized, returning empty hedge pairs");
                return new Dictionary<string, HedgePair>();
            }

            lock (_lockObject)
            {
                try
                {
                    _hedgePairs.Clear();

                    // 获取主账号所有持仓
                    var mainPositions = GetOpenPositions(_mainClient);
                    if (mainPositions == null || mainPositions.Count == 0)
                        return _hedgePairs;

                    // 获取从账号所有持仓
                    var followPositions = GetOpenPositions(_followClient);
                    if (followPositions == null || followPositions.Count == 0)
                        return _hedgePairs;

                    // 匹配对冲仓位
                    foreach (var mainPos in mainPositions)
                    {
                        // 查找匹配的从账号仓位
                        var matchingFollow = followPositions.FirstOrDefault(f =>
                            IsMatchingHedgePair(mainPos, f, _settings.TimeWindowSeconds));

                        if (matchingFollow != null)
                        {
                            var pair = new HedgePair
                            {
                                MainTicket = mainPos.Ticket,
                                FollowTicket = matchingFollow.Ticket,
                                MainSymbol = mainPos.Symbol,
                                FollowSymbol = matchingFollow.Symbol,
                                MainVolume = mainPos.Volume,
                                FollowVolume = matchingFollow.Volume,
                                MainOpenTime = mainPos.Time,
                                FollowOpenTime = matchingFollow.Time,
                                MainType = mainPos.PositionType,
                                FollowType = matchingFollow.PositionType
                            };

                            if (pair.IsValidHedge())
                            {
                                _hedgePairs[pair.GetPairId()] = pair;
                                Logger.Debug($"识别到对冲仓位对: {pair}");
                            }
                        }
                    }

                    Logger.Info($"共识别到 {_hedgePairs.Count} 个对冲仓位对");
                    return _hedgePairs;
                }
                catch (Exception ex)
                {
                    Logger.Error(ex, "识别对冲仓位对时发生错误");
                    OnError?.Invoke(this, $"识别对冲仓位对失败: {ex.Message}");
                    return _hedgePairs;
                }
            }
        }

        /// <summary>
        /// 计算总交易成本
        /// </summary>
        public double CalculateTotalCost(HedgePair pair)
        {
            try
            {
                // 获取实时点差
                double mainSpread = GetSymbolSpread(_mainClient, pair.MainSymbol);
                double followSpread = GetSymbolSpread(_followClient, pair.FollowSymbol);

                // 使用历史平均滑点或默认值
                double mainSlippage = pair.AverageSlippage > 0 ? pair.AverageSlippage : _settings.DefaultSlippage;
                double followSlippage = pair.AverageSlippage > 0 ? pair.AverageSlippage : _settings.DefaultSlippage;

                // 计算点值
                double mainTickValue = CalculateTickValue(pair.MainSymbol, pair.MainVolume, _mainClient);
                double followTickValue = CalculateTickValue(pair.FollowSymbol, pair.FollowVolume, _followClient);

                // 计算滑点成本
                double slippageCost = (mainSlippage * mainTickValue) + (followSlippage * followTickValue);

                // 计算点差成本
                double spreadCost = (mainSpread * mainTickValue) + (followSpread * followTickValue);

                return slippageCost + spreadCost;
            }
            catch (Exception ex)
            {
                Logger.Error(ex, $"计算交易成本失败: {pair.GetPairId()}");
                return 0;
            }
        }

        /// <summary>
        /// 执行原子平仓
        /// </summary>
        public async Task<bool> ExecuteAtomicClose(HedgePair pair)
        {
            if (pair == null) return false;

            if (_mainClient == null || _followClient == null)
            {
                Logger.Error("MT5 clients not initialized, cannot close hedge pair");
                return false;
            }

            lock (_lockObject)
            {
                try
                {
                    Logger.Info($"开始执行原子平仓: {pair.GetPairId()}");

                    // 并行执行平仓
                    var mainCloseTask = Task.Run(() => ClosePosition(_mainClient, pair.MainTicket));
                    var followCloseTask = Task.Run(() => ClosePosition(_followClient, pair.FollowTicket));

                    // 等待两个操作完成
                    var tasks = new[] { mainCloseTask, followCloseTask };
                    var completedTask = Task.WaitAll(tasks, _settings.CloseTimeoutMs);

                    if (!completedTask)
                    {
                        Logger.Error($"平仓超时: {pair.GetPairId()}");
                        return false;
                    }

                    bool mainSuccess = mainCloseTask.Result;
                    bool followSuccess = followCloseTask.Result;

                    if (mainSuccess && followSuccess)
                    {
                        Logger.Info($"原子平仓成功: {pair.GetPairId()}");
                        OnHedgePairClosed?.Invoke(this, pair);
                        _hedgePairs.Remove(pair.GetPairId());
                        return true;
                    }
                    else
                    {
                        // 如果只有一边成功，尝试回滚或重试
                        if (mainSuccess && !followSuccess)
                        {
                            Logger.Warn($"从账号平仓失败，尝试重试: {pair.GetPairId()}");
                            pair.IncrementRetryCount();

                            if (pair.RetryCount <= _settings.MaxRetryCount)
                            {
                                followSuccess = ClosePosition(_followClient, pair.FollowTicket);
                            }
                        }
                        else if (!mainSuccess && followSuccess)
                        {
                            Logger.Warn($"主账号平仓失败，尝试重试: {pair.GetPairId()}");
                            pair.IncrementRetryCount();

                            if (pair.RetryCount <= _settings.MaxRetryCount)
                            {
                                mainSuccess = ClosePosition(_mainClient, pair.MainTicket);
                            }
                        }

                        return mainSuccess && followSuccess;
                    }
                }
                catch (Exception ex)
                {
                    Logger.Error(ex, $"执行原子平仓失败: {pair.GetPairId()}");
                    return false;
                }
            }
        }

        /// <summary>
        /// 监控组合盈亏
        /// </summary>
        private void MonitorTimer_Elapsed(object sender, ElapsedEventArgs e)
        {
            if (!_isMonitoring || _settings.EmergencyStop)
                return;

            try
            {
                // 识别对冲仓位对
                if (_hedgePairs.Count == 0)
                {
                    IdentifyHedgePairs();
                }

                // 检查每个对冲对
                foreach (var pair in _hedgePairs.Values.ToList())
                {
                    CheckAndClosePair(pair);
                }

                _lastCheckTime = DateTime.Now;
            }
            catch (Exception ex)
            {
                Logger.Error(ex, "监控组合盈亏时发生错误");
            }
        }

        /// <summary>
        /// 检查并平仓单个对冲对
        /// </summary>
        private async void CheckAndClosePair(HedgePair pair)
        {
            try
            {
                var startTime = DateTime.Now;

                // 检查最小持仓时间
                if ((DateTime.Now - pair.MainOpenTime).TotalSeconds < _settings.MinHoldingTimeSeconds)
                    return;

                // 获取实时盈亏
                double mainPnL = GetPositionPnL(_mainClient, pair.MainTicket);
                double followPnL = GetPositionPnL(_followClient, pair.FollowTicket);

                // 计算成本
                double totalCost = CalculateTotalCost(pair);

                // 创建结果对象
                var result = new CombinedPnLResult
                {
                    PairId = pair.GetPairId(),
                    MainPnL = mainPnL,
                    FollowPnL = followPnL,
                    TotalCost = totalCost,
                    SafetyFactor = _settings.SafetyFactor,
                    TargetAmount = _settings.TargetNetProfit,
                    CalculationTimeMs = (DateTime.Now - startTime).TotalMilliseconds
                };

                // 计算净盈亏
                result.CalculateNetPnL();

                // 触发事件
                OnPnLCalculated?.Invoke(this, result);

                // 记录日志
                if (_settings.EnableDetailedLogging)
                {
                    Logger.Debug(result.GetLogSummary());
                }

                // 判断是否需要平仓
                if (result.ShouldClose)
                {
                    Logger.Info($"达到平仓条件，准备平仓: {result.GetLogSummary()}");

                    bool closeSuccess = await ExecuteAtomicClose(pair);
                    if (!closeSuccess)
                    {
                        Logger.Warn($"平仓失败，将在下次检查时重试: {pair.GetPairId()}");
                    }
                }

                // 检查最大亏损限制
                if (result.NetPnL <= _settings.MaxLossLimit)
                {
                    Logger.Error($"达到最大亏损限制 {_settings.MaxLossLimit}，触发紧急停止");
                    _settings.EmergencyStop = true;
                    StopMonitoring();
                }

                pair.UpdateCheckTime();
            }
            catch (Exception ex)
            {
                Logger.Error(ex, $"检查对冲对时发生错误: {pair.GetPairId()}");
            }
        }

        #region 辅助方法

        /// <summary>
        /// 获取开仓仓位
        /// </summary>
        private List<MqlTradePosition> GetOpenPositions(MtApi5Client client)
        {
            try
            {
                var positions = new List<MqlTradePosition>();
                int total = client.PositionsTotal();

                for (int i = 0; i < total; i++)
                {
                    ulong ticket = client.PositionGetTicket(i);
                    if (ticket > 0)
                    {
                        var position = GetPositionByTicket(client, ticket);
                        if (position != null)
                            positions.Add(position);
                    }
                }

                return positions;
            }
            catch (Exception ex)
            {
                Logger.Error(ex, "获取开仓仓位失败");
                return new List<MqlTradePosition>();
            }
        }

        /// <summary>
        /// 根据票号获取仓位信息
        /// </summary>
        private MqlTradePosition GetPositionByTicket(MtApi5Client client, ulong ticket)
        {
            try
            {
                if (client.PositionSelectByTicket(ticket))
                {
                    return new MqlTradePosition
                    {
                        Ticket = ticket,
                        Symbol = client.PositionGetString(ENUM_POSITION_PROPERTY_STRING.POSITION_SYMBOL),
                        Volume = client.PositionGetDouble(ENUM_POSITION_PROPERTY_DOUBLE.POSITION_VOLUME),
                        Time = DateTimeOffset.FromUnixTimeSeconds((long)client.PositionGetInteger(ENUM_POSITION_PROPERTY_INTEGER.POSITION_TIME)).DateTime,
                        PositionType = (int)client.PositionGetInteger(ENUM_POSITION_PROPERTY_INTEGER.POSITION_TYPE),
                        Profit = client.PositionGetDouble(ENUM_POSITION_PROPERTY_DOUBLE.POSITION_PROFIT)
                    };
                }
            }
            catch (Exception ex)
            {
                Logger.Error(ex, $"获取仓位信息失败: {ticket}");
            }

            return null;
        }

        /// <summary>
        /// 判断是否匹配的对冲仓位对
        /// </summary>
        private bool IsMatchingHedgePair(MqlTradePosition mainPos, MqlTradePosition followPos, double timeWindowSeconds)
        {
            // 检查品种是否匹配（考虑映射）
            if (!IsSymbolMatch(mainPos.Symbol, followPos.Symbol))
                return false;

            // 检查时间窗口
            double timeDiff = Math.Abs((mainPos.Time - followPos.Time).TotalSeconds);
            if (timeDiff > timeWindowSeconds)
                return false;

            // 检查方向是否相反（对冲）
            if (mainPos.PositionType == followPos.PositionType)
                return false;

            return true;
        }

        /// <summary>
        /// 判断品种是否匹配
        /// </summary>
        private bool IsSymbolMatch(string mainSymbol, string followSymbol)
        {
            // TODO: 实现品种映射逻辑
            // 暂时使用简单的字符串匹配
            return mainSymbol.Replace(".", "") == followSymbol.Replace(".", "");
        }

        /// <summary>
        /// 获取仓位盈亏
        /// </summary>
        public double GetPositionPnL(MtApi5Client client, ulong ticket)
        {
            if (client == null)
            {
                Logger.Warn("Client is null, returning 0 PnL");
                return 0;
            }

            try
            {
                if (client.PositionSelectByTicket(ticket))
                {
                    return client.PositionGetDouble(ENUM_POSITION_PROPERTY_DOUBLE.POSITION_PROFIT);
                }
            }
            catch (Exception ex)
            {
                Logger.Error(ex, $"获取仓位盈亏失败: {ticket}");
            }

            return 0;
        }

        /// <summary>
        /// 获取品种点差
        /// </summary>
        private double GetSymbolSpread(MtApi5Client client, string symbol)
        {
            try
            {
                long spread = client.SymbolInfoInteger(symbol, ENUM_SYMBOL_INFO_INTEGER.SYMBOL_SPREAD);
                return (double)spread;
            }
            catch (Exception ex)
            {
                Logger.Error(ex, $"获取品种点差失败: {symbol}");
            }

            return 0;
        }

        /// <summary>
        /// 计算每点价值
        /// </summary>
        private double CalculateTickValue(string symbol, double volume, MtApi5Client mtClient)
        {
            try
            {
                // 获取合约规格
                double contractSize = 100000; // 默认标准手
                double size = mtClient.SymbolInfoDouble(symbol, ENUM_SYMBOL_INFO_DOUBLE.SYMBOL_TRADE_CONTRACT_SIZE);
                if (size > 0)
                {
                    contractSize = size;
                }

                // 获取最小变动单位
                double tickSize = 0.00001; // 默认5位小数
                double tick = mtClient.SymbolInfoDouble(symbol, ENUM_SYMBOL_INFO_DOUBLE.SYMBOL_TRADE_TICK_SIZE);
                if (tick > 0)
                {
                    tickSize = tick;
                }

                // 对于外汇对，计算USD价值
                if (symbol.Contains("USD"))
                {
                    if (symbol.StartsWith("USD"))
                    {
                        // USD是基础货币，需要除以当前价格
                        double price = mtClient.SymbolInfoDouble(symbol, ENUM_SYMBOL_INFO_DOUBLE.SYMBOL_BID);
                        if (price > 0)
                        {
                            return volume * contractSize * tickSize / price;
                        }
                    }
                    else
                    {
                        // USD是报价货币，直接计算
                        return volume * contractSize * tickSize;
                    }
                }
                else
                {
                    // 非USD货币对，需要转换
                    // TODO: 实现更复杂的货币转换逻辑
                    return volume * contractSize * tickSize;
                }
            }
            catch (Exception ex)
            {
                Logger.Error(ex, $"计算点值失败: {symbol}");
            }

            return 0;
        }

        /// <summary>
        /// 平仓
        /// </summary>
        private bool ClosePosition(MtApi5Client client, ulong ticket)
        {
            try
            {
                MqlTradeRequest request = new MqlTradeRequest
                {
                    Action = ENUM_TRADE_REQUEST_ACTIONS.TRADE_ACTION_DEAL,
                    Position = ticket,
                    Type = ENUM_ORDER_TYPE.ORDER_TYPE_CLOSE_BY
                };

                MqlTradeResult result = null;

                if (client.OrderSend(request, out result))
                {
                    if (result.Retcode == 10009 || result.Retcode == 10008) // TRADE_RETCODE_DONE or TRADE_RETCODE_PLACED
                    {
                        Logger.Info($"平仓成功: Ticket={ticket}");
                        return true;
                    }
                }

                Logger.Warn($"平仓失败: Ticket={ticket}, Retcode={result?.Retcode ?? 0}");
                return false;
            }
            catch (Exception ex)
            {
                Logger.Error(ex, $"平仓异常: {ticket}");
                return false;
            }
        }

        #endregion

        /// <summary>
        /// 仓位信息内部类
        /// </summary>
        private class MqlTradePosition
        {
            public ulong Ticket { get; set; }
            public string Symbol { get; set; }
            public double Volume { get; set; }
            public DateTime Time { get; set; }
            public int PositionType { get; set; }
            public double Profit { get; set; }
        }
    }
}